import types
from datetime import datetime
from decimal import Decimal
from enum import Enum, unique
from typing import Text, Dict, Callable, Union, Optional, List, Any
from dataclasses import dataclass
from pydantic import BaseModel, Field


class WalmartMoniotorType(Enum):
    """ 沃尔玛侵权监控 """
    WFSNOSALE = ('WFSNOSALE','直发店铺禁售sku')
    WFSIMITATIONLAWFIRM = ('WFSIMITATIONLAWFIRM','直发店铺仿牌律所')
    NOSALE = ('NOSALE','非直发店铺禁售sku')
    IMITATIONLAWFIRM = ('IMITATIONLAWFIRM','非直发店铺仿牌律所')


class AllegroEan(Enum):
    """ 沃尔玛侵权监控 """
    ALLEGRO_LISTING_SOURCE_ID_EAN_REPEAT = 't_allegro_listing_source_id_ean_repeat'
    ALLEGRO_LISTING_SOURCE_ID_SKU_REPEAT = 't_allegro_listing_source_id_sku_repeat'
    ALLEGRO_LISTING_COMPANY_EAN_REPEAT = 't_allegro_listing_company_ean_repeat'
    ALLEGRO_LISTING_COMPANY_SKU_REPEAT = 't_allegro_listing_company_sku_repeat'

class SensitiveAuditPriorityJob(Enum):
    """侵权词优先级队列"""
    WALMART = 'walmart_listing'
    ALLEGRO = 'allegro_listing'
    SHOPEE = 'shopee_listing'
    LAZADA = 'lazada_listing'
    ALIEXPRESS = 'aliexpress_listing'
@dataclass
class TestMetrics:
    """ 用例执行数据 """
    passed: int
    failed: int
    broken: int
    skipped: int
    total: int
    pass_rate: float
    time: Text


class RequestType(Enum):
    """
    request请求发送，请求参数的数据类型
    """
    JSON = "JSON"
    PARAMS = "PARAMS"
    DATA = "DATA"
    FILE = 'FILE'
    EXPORT = "EXPORT"
    NONE = "NONE"


class TestCaseEnum(Enum):
    URL = ("url", True)
    HOST = ("host", True)
    METHOD = ("method", True)
    DETAIL = ("detail", True)
    IS_RUN = ("is_run", True)
    HEADERS = ("headers", True)
    REQUEST_TYPE = ("requestType", True)
    DATA = ("data", True)
    DE_CASE = ("dependence_case", True)
    DE_CASE_DATA = ("dependence_case_data", False)
    CURRENT_RE_SET_CACHE = ("current_request_set_cache", False)
    SQL = ("sql", False)
    ASSERT_DATA = ("assert", True)
    SETUP_SQL = ("setup_sql", False)
    TEARDOWN = ("teardown", False)
    TEARDOWN_SQL = ("teardown_sql", False)
    SLEEP = ("sleep", False)


class Method(Enum):
    GET = "GET"
    POST = "POST"
    PUT = "PUT"
    PATCH = "PATCH"
    DELETE = "DELETE"
    HEAD = "HEAD"
    OPTION = "OPTION"


def load_module_functions(module) -> Dict[Text, Callable]:
    """ 获取 module中方法的名称和所在的内存地址 """
    module_functions = {}

    for name, item in vars(module).items():
        if isinstance(item, types.FunctionType):
            module_functions[name] = item
    return module_functions


@unique
class DependentType(Enum):
    """
    数据依赖相关枚举
    """
    RESPONSE = 'response'
    REQUEST = 'request'
    SQL_DATA = 'sqlData'
    CACHE = "cache"


class Assert(BaseModel):
    jsonpath: Text
    type: Text
    value: Any
    AssertType: Union[None, Text] = None


class DependentData(BaseModel):
    dependent_type: Text
    jsonpath: Text
    set_cache: Optional[Text]
    replace_key: Optional[Text]


class DependentCaseData(BaseModel):
    case_id: Text
    # dependent_data: List[DependentData]
    dependent_data: Union[None, List[DependentData]] = None


class ParamPrepare(BaseModel):
    dependent_type: Text
    jsonpath: Text
    set_cache: Text


class SendRequest(BaseModel):
    dependent_type: Text
    jsonpath: Optional[Text]
    cache_data: Optional[Text]
    set_cache: Optional[Text]
    replace_key: Optional[Text]


class TearDown(BaseModel):
    case_id: Text
    param_prepare: Optional[List["ParamPrepare"]]
    send_request: Optional[List["SendRequest"]]


class CurrentRequestSetCache(BaseModel):
    type: Text
    jsonpath: Text
    name: Text


class TestCase(BaseModel):
    url: Text
    method: Text
    detail: Text
    # assert_data: Union[Dict, Text] = Field(..., alias="assert")
    assert_data: Union[Dict, Text]
    headers: Union[None, Dict, Text] = {}
    requestType: Text
    is_run: Union[None, bool, Text] = None
    data: Any = None
    dependence_case: Union[None, bool] = False
    dependence_case_data: Optional[Union[None, List["DependentCaseData"], Text]] = None
    sql: List = None
    setup_sql: List = None
    status_code: Optional[int] = None
    teardown_sql: Optional[List] = None
    teardown: Union[List["TearDown"], None] = None
    current_request_set_cache: Optional[List["CurrentRequestSetCache"]]
    sleep: Optional[Union[int, float]]


class ResponseData(BaseModel):
    url: Text
    is_run: Union[None, bool, Text]
    detail: Text
    response_data: Text
    request_body: Any
    method: Text
    sql_data: Dict
    yaml_data: "TestCase"
    headers: Dict
    cookie: Dict
    assert_data: Dict
    res_time: Union[int, float]
    status_code: int
    teardown: List["TearDown"] = None
    teardown_sql: Union[None, List]
    body: Any


class DingTalk(BaseModel):
    webhook: Union[Text, None]
    secret: Union[Text, None]


class MySqlDB(BaseModel):
    switch: bool = False
    host: Union[Text, None] = None
    user: Union[Text, None] = None
    password: Union[Text, None] = None
    port: Union[int, None] = 3306


class Webhook(BaseModel):
    webhook: Union[Text, None]


class Email(BaseModel):
    send_user: Union[Text, None]
    email_host: Union[Text, None]
    stamp_key: Union[Text, None]
    # 收件人
    send_list: Union[Text, None]


class Config(BaseModel):
    project_name: Text
    env: Text
    tester_name: Text
    notification_type: Text = '0'
    excel_report: bool
    ding_talk: "DingTalk"
    mysql_db: "MySqlDB"
    mirror_source: Text
    wechat: "Webhook"
    email: "Email"
    lark: "Webhook"
    real_time_update_test_cases: bool = False
    host: Text
    app_host: Union[Text, None]


@unique
class AllureAttachmentType(Enum):
    """
    allure 报告的文件类型枚举
    """
    TEXT = "txt"
    CSV = "csv"
    TSV = "tsv"
    URI_LIST = "uri"

    HTML = "html"
    XML = "xml"
    JSON = "json"
    YAML = "yaml"
    PCAP = "pcap"

    PNG = "png"
    JPG = "jpg"
    SVG = "svg"
    GIF = "gif"
    BMP = "bmp"
    TIFF = "tiff"

    MP4 = "mp4"
    OGG = "ogg"
    WEBM = "webm"

    PDF = "pdf"


@unique
class AssertMethod(Enum):
    """断言类型"""
    equals = "=="
    less_than = "lt"
    less_than_or_equals = "le"
    greater_than = "gt"
    greater_than_or_equals = "ge"
    not_equals = "not_eq"
    string_equals = "str_eq"
    length_equals = "len_eq"
    length_greater_than = "len_gt"
    length_greater_than_or_equals = 'len_ge'
    length_less_than = "len_lt"
    length_less_than_or_equals = 'len_le'
    contains = "contains"
    contained_by = 'contained_by'
    startswith = 'startswith'
    endswith = 'endswith'


class AllegroListingFilterTemplate(BaseModel):
    id: int
    template_name: str
    status: int
    template_type: Optional[int]
    listing_publish_start_time: Union[datetime, None]
    listing_publish_end_time: Union[datetime, None]
    price_min: Union[Decimal,None] = None
    price_max: Union[Decimal,None] = None
    listing_sale_min: Optional[int]
    listing_sale_max: Optional[int]
    listing_sale_recent_days: Optional[int]
    sku_sale_min: Optional[int]
    sku_sale_max: Optional[int]
    sku_sale_recent_days: Optional[int]
    has_published: Optional[str] = '0'
    in_promotion: Optional[int] = 2
    listing_discount_min: Optional[int]
    listing_discount_max: Optional[int]
    listing_discount_type: Optional[int]
    available_stock_min: Optional[int]
    available_stock_max: Optional[int]
    sku_listing_number: Optional[int]
    sku_active_number: Optional[int]
    filter_active_sku: Optional[int] = 0
    source_sku_sale_min: Optional[int]
    source_sku_sale_max: Optional[int]
    source_sku_sale_recent_days: Optional[int]
    no_sale: Optional[int]
    warehouse_id_list: Optional[str]
    listing_quantity_min: Optional[int]
    listing_quantity_max: Optional[int]
    listing_thirty_sales_min: Optional[int]
    listing_thirty_sales_max: Optional[int]
    listing_sixty_sales_min: Optional[int]
    listing_sixty_sales_max: Optional[int]
    listing_ninety_sales_min: Optional[int]
    listing_ninety_sales_max: Optional[int]
    listing_total_sales_min: Optional[int]
    listing_total_sales_max: Optional[int]
    watchers_count_min: Optional[int]
    watchers_count_max: Optional[int]
    watchers_conversion_rate_min: Union[Decimal,None] = None
    watchers_conversion_rate_max: Union[Decimal,None] = None
    thirty_sales_conversion_rate_min: Union[Decimal,None] = None
    thirty_sales_conversion_rate_max: Union[Decimal,None] = None
    visits_count_min: Optional[int]
    visits_count_max: Optional[int]
    prohibit_platform_types: Union[str,None]
    prohibit_platform_sites: Union[str,None]
    risk_level_type: Optional[int]
    risk_level_platform_types: Union[str,None]
    risk_level_platform_sites: Union[str,None]

class StrategyRuleAllegro(BaseModel):
    id: int
    strategy_id: int
    execute_sort: int = Field(default=10, ge=0, description='执行顺序')
    rule_code: str = Field(default='', max_length=100, description='规则类型编码')
    execute_type: int = Field(default=0, description='规则执行类型')
    is_driver_table: bool = Field(default=False, description='是否驱动数据表')
    status: int = Field(default=1, ge=0, le=1, description='模板状态')
    filter_val: str = Field(default='', max_length=64, description='规则值')
    filter_min_val: str = Field(default='', max_length=30, description='最小值')
    filter_max_val: str = Field(default='', max_length=30, description='最大值')
    filter_express: str = Field(default='', max_length=30, description='规则表达式')
    remark: Optional[str] = Field(None, max_length=100, description='备注')
    create_by: Optional[int]
    create_name: Optional[str] = Field(None, max_length=50, description='创建人名称')
    create_time: Optional[datetime] = Field(default_factory=datetime.now, description='创建时间')
    update_by: Optional[int]
    update_name: Optional[str] = Field(None, max_length=50, description='修改人名称')
    update_time: Optional[datetime] = Field(default_factory=datetime.now, description='修改人时间')
    is_deleted: bool = Field(default=False, description='是否已删除')

    class Config:
        orm_mode = True

class StrategyRuleTemuOne(BaseModel):
    id: int
    strategy_id: int
    execute_sort: int = 10
    rule_code: str = ''
    execute_type: int = 0
    is_driver_table: bool = False
    status: int = 1
    filter_val: str = ''
    filter_min_val: str = ''
    filter_max_val: str = ''
    filter_express: str = ''


class StrategyRuleTemu(BaseModel):
    publish_type: StrategyRuleTemuOne
    product_model: StrategyRuleTemuOne
    sku_available_stock: StrategyRuleTemuOne
    pf_no_sale_site: StrategyRuleTemuOne
    product_risk_level: StrategyRuleTemuOne
    sku_republish_detect: StrategyRuleTemuOne
    price_calculator_set_value: StrategyRuleTemuOne
    saleable_num: StrategyRuleTemuOne
    sku_list: Optional[list[str]]=None